home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2008 February / PCWFEB08.iso / Software / Freeware / Miro 1.0 / Miro_Installer.exe / Miro_Downloader.exe / test / templatetest.pyc (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2007-11-12  |  21.4 KB  |  543 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.5)
  3.  
  4. import unittest
  5. import resources
  6. import os
  7. import re
  8. import time
  9. import copy
  10. import feedparser
  11. import feed
  12. import item
  13. import app
  14. import maps
  15. from template import *
  16. import templateoptimize
  17. from time import time
  18. import database
  19. import gettext
  20. import compiled_templates
  21. from test.framework import DemocracyTestCase
  22. ranOnUnload = 0
  23. HTMLPattern = re.compile('^.*<body.*?>(.*)</body\\s*>', re.S)
  24.  
  25. class HTMLObject(database.DDBObject):
  26.     
  27.     def __init__(self, html):
  28.         self.html = html
  29.         database.DDBObject.__init__(self)
  30.  
  31.  
  32.  
  33. class DOMTracker:
  34.     
  35.     def __init__(self):
  36.         self.callList = []
  37.  
  38.     
  39.     def addItemAtEnd(self, xml, id):
  40.         self.callList.append({
  41.             'name': 'addItemAtEnd',
  42.             'xml': xml,
  43.             'id': id })
  44.  
  45.     
  46.     def addItemBefore(self, xml, id):
  47.         self.callList.append({
  48.             'name': 'addItemBefore',
  49.             'xml': xml,
  50.             'id': id })
  51.  
  52.     
  53.     def removeItem(self, id):
  54.         self.callList.append({
  55.             'name': 'removeItem',
  56.             'id': id })
  57.  
  58.     
  59.     def removeItems(self, ids):
  60.         self.callList.append({
  61.             'name': 'removeItems',
  62.             'ids': ids })
  63.  
  64.     
  65.     def changeItem(self, id, xml, changeHint):
  66.         self.callList.append({
  67.             'name': 'changeItem',
  68.             'xml': xml,
  69.             'id': id,
  70.             'changeHint': changeHint })
  71.  
  72.     
  73.     def changeItems(self, pairs):
  74.         self.callList.append({
  75.             'name': 'changeItems',
  76.             'pairs': pairs })
  77.  
  78.     
  79.     def hideItem(self, id):
  80.         self.callList.append({
  81.             'name': 'hideItem',
  82.             'id': id })
  83.  
  84.     
  85.     def showItem(self, id):
  86.         self.callList.append({
  87.             'name': 'showItem',
  88.             'id': id })
  89.  
  90.  
  91.  
  92. class ChangeDelayedDOMTracker(DOMTracker):
  93.     
  94.     def changeItem(self, id, xml):
  95.         time.sleep(0.1)
  96.         self.callList.append({
  97.             'name': 'changeItem',
  98.             'xml': xml,
  99.             'id': id })
  100.  
  101.  
  102.  
  103. class SimpleTest(DemocracyTestCase):
  104.     
  105.     def setUp(self):
  106.         handle = file(resources.path('templates/unittest/simple'), 'r')
  107.         self.text = handle.read()
  108.         handle.close()
  109.         self.text = HTMLPattern.match(self.text).group(1)
  110.  
  111.     
  112.     def test(self):
  113.         (tch, handle) = fillTemplate('unittest/simple', DOMTracker(), 'gtk-x11-MozillaBrowser', 'platform')
  114.         text = tch.read()
  115.         text = HTMLPattern.match(text).group(1)
  116.         self.assertEqual(text, self.text)
  117.  
  118.     
  119.     def testExecuteTemplate(self):
  120.         (tch, handle) = fillTemplate('unittest/execute-template', DOMTracker(), 'gtk-x11-MozillaBrowser', 'platform')
  121.         text = tch.read()
  122.         text = HTMLPattern.match(text).group(1)
  123.         testRE = re.compile('^\\s+<span>foo</span>\\s+<span>BAR</span>\\s+$')
  124.         self.assert_(testRE.match(text))
  125.  
  126.  
  127.  
  128. class TranslationTest(DemocracyTestCase):
  129.     
  130.     def setUp(self):
  131.         handle = file(resources.path('testdata/translation-result'), 'r')
  132.         self.text = handle.read()
  133.         handle.close()
  134.         self.text = HTMLPattern.match(self.text).group(1)
  135.         self.oldgettext = gettext.gettext
  136.  
  137.     
  138.     def tearDown(self):
  139.         compiled_templates.unittest.translationtest._ = self.oldgettext
  140.         DemocracyTestCase.tearDown(self)
  141.  
  142.     
  143.     def test(self):
  144.         
  145.         compiled_templates.unittest.translationtest._ = lambda x: '!%s!' % x
  146.         (tch, handle) = fillTemplate('unittest/translationtest', DOMTracker(), 'gtk-x11-MozillaBrowser', 'platform')
  147.         compiled_templates.unittest.translationtest._ = self.oldgettext
  148.         text = tch.read()
  149.         text = HTMLPattern.match(text).group(1)
  150.         self.assertEqual(text, self.text)
  151.  
  152.  
  153.  
  154. class ReplaceTest(DemocracyTestCase):
  155.     
  156.     def setUp(self):
  157.         handle = file(resources.path('testdata/replace-result'), 'r')
  158.         self.text = handle.read()
  159.         handle.close()
  160.         self.text = HTMLPattern.match(self.text).group(1)
  161.  
  162.     
  163.     def test(self):
  164.         (tch, handle) = fillTemplate('unittest/replace', DOMTracker(), 'gtk-x11-MozillaBrowser', 'platform')
  165.         text = tch.read()
  166.         text = HTMLPattern.match(text).group(1)
  167.         self.assertEqual(text, self.text)
  168.  
  169.  
  170.  
  171. class HideTest(DemocracyTestCase):
  172.     
  173.     def setUp(self):
  174.         DemocracyTestCase.setUp(self)
  175.         handle = file(resources.path('testdata/hide-result'), 'r')
  176.         self.text = handle.read()
  177.         handle.close()
  178.         self.text = HTMLPattern.match(self.text).group(1)
  179.  
  180.     
  181.     def test(self):
  182.         (tch, handle) = fillTemplate('unittest/hide', DOMTracker(), 'gtk-x11-MozillaBrowser', 'platform')
  183.         text = tch.read()
  184.         text = HTMLPattern.match(text).group(1)
  185.         self.assertEqual(text, self.text)
  186.  
  187.  
  188.  
  189. class ViewTest(DemocracyTestCase):
  190.     pattern = re.compile('^\n<h1>view test template</h1>\n<span id="([^"]+)"/>\n', re.S)
  191.     containerPattern = re.compile('^\n<h1>view test template</h1>\n<div id="([^"]+)"></div>\n', re.S)
  192.     doublePattern = re.compile('^\n<h1>view test template</h1>\n<span id="([^"]+)"/>\n<span id="([^"]+)"/>\n', re.S)
  193.     updatePattern = re.compile('^\n<h1>update test template</h1>\n<span id="([^"]+)"/>\n', re.S)
  194.     hidePattern = re.compile('^\n<h1>update hide test template</h1>\n<div class="foo" id="([^"]+)"', re.S)
  195.     itemPattern = re.compile('<div id="(.*?)">\n<span>testview\\d*</span>\n<span><span>object</span></span>\n<span><span>object</span></span>\n\n<div>\nhideIf:False\n<span>This is an include</span>\n\n<span>This is a template include</span>\n\n<span><span>This is a database replace</span></span>\n<span><span>This is a database replace</span></span>\n</div>\n</div>', re.S)
  196.     
  197.     def setUp(self):
  198.         global ranOnUnload
  199.         ranOnUnload = 0
  200.         DemocracyTestCase.setUp(self)
  201.         self.everything = database.defaultDatabase
  202.         self.x = HTMLObject('<span>object</span>')
  203.         self.y = HTMLObject('<span>object</span>')
  204.         self.domHandle = DOMTracker()
  205.  
  206.     
  207.     def test(self):
  208.         (tch, handle) = fillTemplate('unittest/view', self.domHandle, 'gtk-x11-MozillaBrowser', 'platform')
  209.         text = tch.read()
  210.         text = HTMLPattern.match(text).group(1)
  211.         self.assert_(self.pattern.match(text))
  212.         id = self.pattern.match(text).group(1)
  213.         handle.initialFillIn()
  214.         self.assertEqual(len(self.domHandle.callList), 1)
  215.         self.assertEqual(self.domHandle.callList[0]['name'], 'addItemBefore')
  216.         self.assertEqual(self.domHandle.callList[0]['id'], id)
  217.         match = self.itemPattern.findall(self.domHandle.callList[0]['xml'])
  218.         self.assertEqual(len(match), 2)
  219.         self.assertNotEqual(match[0], match[1])
  220.         self.assertEqual(ranOnUnload, 0)
  221.         handle.unlinkTemplate()
  222.         self.assertEqual(ranOnUnload, 1)
  223.  
  224.     
  225.     def testContainerDiv(self):
  226.         (tch, handle) = fillTemplate('unittest/view-container-div', self.domHandle, 'gtk-x11-MozillaBrowser', 'platform')
  227.         text = tch.read()
  228.         text = HTMLPattern.match(text).group(1)
  229.         self.assert_(self.containerPattern.match(text))
  230.         id = self.containerPattern.match(text).group(1)
  231.         handle.initialFillIn()
  232.         self.assertEqual(len(self.domHandle.callList), 1)
  233.         self.assertEqual(self.domHandle.callList[0]['name'], 'addItemAtEnd')
  234.         self.assertEqual(self.domHandle.callList[0]['id'], id)
  235.         initialXML = self.domHandle.callList[0]['xml']
  236.         match = self.itemPattern.findall(initialXML)
  237.         self.assertEqual(len(match), 2)
  238.         self.assertNotEqual(match[0], match[1])
  239.         handle.trackedViews[0].onResort()
  240.         self.assertEqual(len(self.domHandle.callList), 3)
  241.         self.assertEqual(self.domHandle.callList[1]['name'], 'changeItem')
  242.         self.assertEqual(self.domHandle.callList[1]['id'], id)
  243.         self.assertEqual(self.domHandle.callList[1]['xml'], '<div id="%s"></div>' % id)
  244.         self.assertEqual(self.domHandle.callList[2]['name'], 'addItemAtEnd')
  245.         self.assertEqual(self.domHandle.callList[2]['id'], id)
  246.         self.assertEqual(self.domHandle.callList[2]['xml'], initialXML)
  247.  
  248.     
  249.     def testUpdate(self):
  250.         (tch, handle) = fillTemplate('unittest/update', self.domHandle, 'gtk-x11-MozillaBrowser', 'platform')
  251.         text = tch.read()
  252.         text = HTMLPattern.match(text).group(1)
  253.         self.assert_(self.updatePattern.match(text))
  254.         id = self.updatePattern.match(text).group(1)
  255.         handle.initialFillIn()
  256.         self.assertEqual(len(self.domHandle.callList), 1)
  257.         self.assertEqual(self.domHandle.callList[0]['name'], 'addItemBefore')
  258.         self.assertEqual(self.domHandle.callList[0]['id'], id)
  259.         match = self.itemPattern.findall(self.domHandle.callList[0]['xml'])
  260.         self.assertEqual(len(match), 1)
  261.         self.x.signalChange()
  262.         handle.updateRegions[0].doChange()
  263.         self.assertEqual(len(self.domHandle.callList), 1)
  264.         self.x.html = '<span>changes object</span>'
  265.         self.x.signalChange()
  266.         handle.updateRegions[0].doChange()
  267.         self.assertEqual(len(self.domHandle.callList), 2)
  268.         self.assertEqual(self.domHandle.callList[1]['name'], 'changeItems')
  269.         self.assertEqual(self.domHandle.callList[1]['pairs'][0][0], match[0])
  270.         temp = HTMLObject('<span>object</span>')
  271.         handle.updateRegions[0].doChange()
  272.         self.assertEqual(len(self.domHandle.callList), 3)
  273.         self.assertEqual(self.domHandle.callList[2]['name'], 'changeItems')
  274.         self.assertEqual(self.domHandle.callList[2]['pairs'][0][0], match[0])
  275.         temp.remove()
  276.         handle.updateRegions[0].doChange()
  277.         self.assertEqual(len(self.domHandle.callList), 4)
  278.         self.assertEqual(self.domHandle.callList[3]['name'], 'changeItems')
  279.         self.assertEqual(self.domHandle.callList[3]['pairs'][0][0], match[0])
  280.         self.assertEqual(ranOnUnload, 0)
  281.         handle.unlinkTemplate()
  282.         self.assertEqual(ranOnUnload, 1)
  283.  
  284.     
  285.     def testHide(self):
  286.         (tch, handle) = fillTemplate('unittest/update-hide', self.domHandle, 'gtk-x11-MozillaBrowser', 'platform')
  287.         text = tch.read()
  288.         text = HTMLPattern.match(text).group(1)
  289.         self.assert_(self.hidePattern.match(text))
  290.         id = self.hidePattern.match(text).group(1)
  291.         handle.initialFillIn()
  292.         self.assertEqual(len(self.domHandle.callList), 0)
  293.         self.x.signalChange()
  294.         self.assertEqual(len(self.domHandle.callList), 0)
  295.         temp = HTMLObject('<span>object</span>')
  296.         self.assertEqual(len(self.domHandle.callList), 1)
  297.         self.assertEqual(self.domHandle.callList[0]['name'], 'showItem')
  298.         self.assertEqual(self.domHandle.callList[0]['id'], id)
  299.         temp.remove()
  300.         self.assertEqual(len(self.domHandle.callList), 2)
  301.         self.assertEqual(self.domHandle.callList[1]['name'], 'hideItem')
  302.         self.assertEqual(self.domHandle.callList[1]['id'], id)
  303.         self.assertEqual(ranOnUnload, 0)
  304.         handle.unlinkTemplate()
  305.         self.assertEqual(ranOnUnload, 1)
  306.  
  307.     
  308.     def testTwoViews(self):
  309.         (tch, handle) = fillTemplate('unittest/view-double', self.domHandle, 'gtk-x11-MozillaBrowser', 'platform')
  310.         text = tch.read()
  311.         text = HTMLPattern.match(text).group(1)
  312.         if not self.doublePattern.match(text):
  313.             raise AssertionError
  314.         id = self.doublePattern.match(text).group(1)
  315.         id2 = self.doublePattern.match(text).group(2)
  316.         handle.initialFillIn()
  317.         self.assertEqual(len(self.domHandle.callList), 2)
  318.         self.assertEqual(self.domHandle.callList[0]['name'], 'addItemBefore')
  319.         self.assertEqual(self.domHandle.callList[1]['name'], 'addItemBefore')
  320.         self.assert_(self.domHandle.callList[0]['id'] != self.domHandle.callList[1]['id'])
  321.         self.assert_(self.domHandle.callList[0]['id'] in [
  322.             id,
  323.             id2])
  324.         self.assert_(self.domHandle.callList[1]['id'] in [
  325.             id,
  326.             id2])
  327.         items1 = self.itemPattern.findall(self.domHandle.callList[0]['xml'])
  328.         items2 = self.itemPattern.findall(self.domHandle.callList[1]['xml'])
  329.         match = copy.copy(items1)
  330.         match.extend(items2)
  331.         self.assertEqual(len(match), 4)
  332.         self.x.signalChange()
  333.         handle.trackedViews[0].callback()
  334.         handle.trackedViews[1].callback()
  335.         self.assertEqual(len(self.domHandle.callList), 2)
  336.         self.x.html = '<span>changed object</span>'
  337.         self.x.signalChange()
  338.         handle.trackedViews[0].callback()
  339.         handle.trackedViews[1].callback()
  340.         self.assertEqual(len(self.domHandle.callList), 4)
  341.         self.x.remove()
  342.         handle.trackedViews[0].callback()
  343.         handle.trackedViews[1].callback()
  344.         self.assertEqual(len(self.domHandle.callList), 6)
  345.         self.assertEqual(self.domHandle.callList[0]['name'], 'addItemBefore')
  346.         self.assertEqual(self.domHandle.callList[1]['name'], 'addItemBefore')
  347.         self.assertEqual(self.domHandle.callList[2]['name'], 'changeItems')
  348.         self.assertEqual(self.domHandle.callList[3]['name'], 'changeItems')
  349.         self.assertEqual(self.domHandle.callList[4]['name'], 'removeItems')
  350.         self.assertEqual(self.domHandle.callList[5]['name'], 'removeItems')
  351.         changed1 = [ p[0] for p in self.domHandle.callList[2]['pairs'] ]
  352.         changed2 = [ p[0] for p in self.domHandle.callList[3]['pairs'] ]
  353.         self.assertEqual(len(changed1), 1)
  354.         self.assertEqual(len(changed2), 1)
  355.         if (changed1[0] in items1 or changed2[0] in items2) and changed1[0] in items2:
  356.             pass
  357.         self.assert_(changed2[0] in items1)
  358.         self.assertEqual(self.domHandle.callList[4]['name'], 'removeItems')
  359.         self.assertEqual(self.domHandle.callList[5]['name'], 'removeItems')
  360.         self.assertEquals(len(self.domHandle.callList[4]['ids']), 1)
  361.         self.assertEquals(len(self.domHandle.callList[5]['ids']), 1)
  362.         if (self.domHandle.callList[4]['ids'][0] in items1 or self.domHandle.callList[5]['ids'][0] in items2) and self.domHandle.callList[4]['ids'][0] in items2:
  363.             pass
  364.         self.assert_(self.domHandle.callList[5]['ids'][0] in items1)
  365.         self.x = HTMLObject('<span>object</span>')
  366.         handle.trackedViews[0].callback()
  367.         handle.trackedViews[1].callback()
  368.         self.assertEqual(len(self.domHandle.callList), 8)
  369.         self.assertEqual(self.domHandle.callList[6]['name'], 'addItemBefore')
  370.         match.extend(self.itemPattern.findall(self.domHandle.callList[6]['xml']))
  371.         self.assertEqual(self.domHandle.callList[7]['name'], 'addItemBefore')
  372.         match.extend(self.itemPattern.findall(self.domHandle.callList[7]['xml']))
  373.         self.assertEqual(len(match), 6)
  374.         for x in range(len(match)):
  375.             for y in range(x + 1, len(match)):
  376.                 self.assertNotEqual(match[x], match[y])
  377.             
  378.         
  379.         self.assertEqual(ranOnUnload, 0)
  380.         handle.unlinkTemplate()
  381.         self.assertEqual(ranOnUnload, 1)
  382.  
  383.  
  384.  
  385. class TemplatePerformance(DemocracyTestCase):
  386.     
  387.     def setUp(self):
  388.         global ranOnUnload
  389.         ranOnUnload = 0
  390.         DemocracyTestCase.setUp(self)
  391.         self.everything = database.defaultDatabase
  392.         self.domHandle = DOMTracker()
  393.  
  394.     
  395.     def timeIt(self, func, repeat):
  396.         start = time()
  397.         for x in xrange(repeat):
  398.             func()
  399.         
  400.         totalTime = time() - start
  401.         return totalTime
  402.  
  403.     
  404.     def testRender(self):
  405.         self.feeds = []
  406.         self.items = []
  407.         for x in range(50):
  408.             self.feeds.append(feed.Feed(u'http://www.getdemocracy.com/50'))
  409.             for y in range(50):
  410.                 self.items.append(item.Item(feedparser.FeedParserDict({
  411.                     'title': u'%d-%d' % (x, y),
  412.                     'enclosures': [
  413.                         {
  414.                             'url': u'file://%d-%d.mpg' % (x, y) }] }), feed_id = self.feeds[-1].id))
  415.             
  416.         
  417.         time1 = self.timeIt(self.fillAndUnlink, 10)
  418.         for x in range(50):
  419.             for y in range(450):
  420.                 self.items.append(item.Item(feedparser.FeedParserDict({
  421.                     'title': u'%d-%d' % (x, y),
  422.                     'enclosures': [
  423.                         {
  424.                             'url': u'file://%d-%d.mpg' % (x, y) }] }), feed_id = self.feeds[x].id))
  425.             
  426.         
  427.         time2 = self.timeIt(self.fillAndUnlink, 10)
  428.         self.assert_(time2 / time1 < 11, 'Template filling does not scale linearly')
  429.  
  430.     
  431.     def fillAndUnlink(self):
  432.         (tch, handle) = fillTemplate('channel', self.domHandle, 'gtk-x11-MozillaBrowser', 'platform', id = self.feeds[-1].getID())
  433.         tch.read()
  434.         handle.initialFillIn()
  435.         handle.unlinkTemplate()
  436.  
  437.  
  438.  
  439. class OptimizedAttributeChangeTest(DemocracyTestCase):
  440.     
  441.     def setUp(self):
  442.         self.changer = templateoptimize.HTMLChangeOptimizer()
  443.  
  444.     
  445.     def checkChange(self, id, newXML, attributesDiff, htmlChanged):
  446.         changes = self.changer.calcChanges('abc123', newXML)
  447.         self.assertEquals(len(changes), 1)
  448.         self.assertEquals(changes[0][0], id)
  449.         self.assertEquals(changes[0][1], newXML)
  450.         self.assertEquals(changes[0][2].changedAttributes, attributesDiff)
  451.         if htmlChanged:
  452.             self.assert_(changes[0][2].changedInnerHTML is not None)
  453.         else:
  454.             self.assert_(changes[0][2].changedInnerHTML is None)
  455.  
  456.     
  457.     def testBigChange(self):
  458.         first = '<div class="item" id="abc123">foo</div>'
  459.         second = '<div class="item" id="abc123">bar</div>'
  460.         self.changer.setInitialHTML('abc123', first)
  461.         self.checkChange('abc123', second, { }, True)
  462.  
  463.     
  464.     def testNoChange(self):
  465.         first = '<div class="item" id="abc123">foo</div>'
  466.         self.changer.setInitialHTML('abc123', first)
  467.         changes = self.changer.calcChanges('abc123', first)
  468.         self.assertEquals(len(changes), 0)
  469.  
  470.     
  471.     def testAttributeChange(self):
  472.         first = '<div class="item" id="abc123">foo</div>'
  473.         second = '<div class="item highlighed" id="abc123">foo</div>'
  474.         self.changer.setInitialHTML('abc123', first)
  475.         self.checkChange('abc123', second, {
  476.             'class': 'item highlighed' }, False)
  477.  
  478.     
  479.     def testMultipleChanges(self):
  480.         first = '<div class="item" id="abc123">foo</div>'
  481.         second = '<div class="item highlighed" id="abc123">foo</div>'
  482.         third = '<div class="item highlighed" id="abc123">bar</div>'
  483.         fourth = '<div class="item" id="abc123">bar</div>'
  484.         self.changer.setInitialHTML('abc123', first)
  485.         self.checkChange('abc123', second, {
  486.             'class': 'item highlighed' }, False)
  487.         self.checkChange('abc123', third, { }, True)
  488.         self.checkChange('abc123', fourth, {
  489.             'class': 'item' }, False)
  490.  
  491.     
  492.     def testChangeWithoutInitalHTML(self):
  493.         first = '<div class="item" id="abc123">foo</div>'
  494.         self.assertRaises(KeyError, self.changer.calcChanges, 'abc123', first)
  495.  
  496.  
  497.  
  498. class HotspotOptimizedTest(DemocracyTestCase):
  499.     
  500.     def setUp(self):
  501.         self.changer = templateoptimize.HTMLChangeOptimizer()
  502.  
  503.     
  504.     def makeHotspotArea(self, outertext, innertext):
  505.         return '<div id="outer">\n   <p>%s</p>\n   <!-- HOT SPOT inner --><span id="inner">%s</span><!-- HOT SPOT END -->\n</div>' % (outertext, innertext)
  506.  
  507.     
  508.     def makeMultiHotspotArea(self, outertext, innertext, innertext2):
  509.         return '<div id="outer">\n   <p>%s</p>\n   <!-- HOT SPOT inner --><span id="inner">%s</span><!-- HOT SPOT END -->\n   <!-- HOT SPOT inner-2 --><span id="inner-2">%s</span><!-- HOT SPOT END -->\n</div>' % (outertext, innertext, innertext2)
  510.  
  511.     
  512.     def checkChange(self, newXML, *shouldChangeIDs):
  513.         changes = self.changer.calcChanges('outer', newXML)
  514.         actuallyChanged = [ c[0] for c in changes ]
  515.         self.assertEquals(set(shouldChangeIDs), set(actuallyChanged))
  516.  
  517.     
  518.     def testHotspotChange(self):
  519.         first = self.makeHotspotArea('booya', 'booyaka')
  520.         second = self.makeHotspotArea('booya', 'booyaka booyaka')
  521.         self.changer.setInitialHTML('outer', first)
  522.         self.checkChange(second, 'inner')
  523.  
  524.     
  525.     def testOutsideHotspotChange(self):
  526.         first = self.makeHotspotArea('foo', 'booyaka')
  527.         second = self.makeHotspotArea('bar', 'booyaka booyaka')
  528.         self.changer.setInitialHTML('outer', first)
  529.         self.checkChange(second, 'outer')
  530.  
  531.     
  532.     def testMultipleHotspots(self):
  533.         first = self.makeMultiHotspotArea('foo', 'apples', 'bananas')
  534.         second = self.makeMultiHotspotArea('foo', 'apples', 'pears')
  535.         third = self.makeMultiHotspotArea('foo', 'kiwi', 'starfruit')
  536.         fourth = self.makeMultiHotspotArea('bar', 'kiwi', 'starfruit')
  537.         self.changer.setInitialHTML('outer', first)
  538.         self.checkChange(second, 'inner-2')
  539.         self.checkChange(third, 'inner', 'inner-2')
  540.         self.checkChange(fourth, 'outer')
  541.  
  542.  
  543.